package tool

import (
	md52 "crypto/md5"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"errors"
	"fmt"
	"github.com/google/uuid"
	"golang.org/x/text/cases"
	"golang.org/x/text/language"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"
)

// StripSymbol 去除符号和特殊字符
func StripSymbol(str, skip, encoding string) string {
	var pattern string
	if encoding == "utf8" {
		pattern = "[\\p{Han}a-zA-Z0-9" + skip + "]+"
	} else {
		pattern = "[\\x80-\\xFFa-zA-Z0-9" + skip + "]+"
	}
	reg := regexp.MustCompile(pattern)
	result := reg.FindAllString(HtmlEntityDecode(str), -1)
	return strings.Join(result, "")
}

// HasChinese 判断是否含有中文
func HasChinese(str, encoding string) bool {
	var pattern string
	if encoding == "utf8" {
		pattern = "[\\p{Han}]+"
	} else {
		pattern = "[\\x80-\\xFF]+"
	}
	reg := regexp.MustCompile(pattern)
	return reg.MatchString(str)
}

// GetSexByIDCard 根据身份证号码判断性别
func GetSexByIDCard(idCard string) (string, error) {
	if len(idCard) != 18 {
		return "", fmt.Errorf("身份证号码长度不正确")
	}
	sexNum := idCard[16:17] // 获取第17位数字
	sexInt, err := strconv.Atoi(sexNum)
	if err != nil {
		return "", fmt.Errorf("身份证号码格式不正确")
	}
	if sexInt%2 == 0 {
		return "女", nil
	} else {
		return "男", nil
	}
}

// 通过身份证号码获取年龄
func GetAgeByIdCard(idCard string) (int, error) {
	if len(idCard) != 18 {
		return 0, errors.New("身份证号码不是18位")
	}
	birthday := fmt.Sprintf("%s-%s-%s", idCard[6:10], idCard[10:12], idCard[12:14])
	return GetAgeByBirthday(birthday)
}

// 通过身份证号码获取出生日期
func GetBirthdayByIdCard(idCard string) (string, error) {
	if len(idCard) != 18 {
		return "", errors.New("身份证号码不是18位")
	}
	birthday := fmt.Sprintf("%s-%s-%s", idCard[6:10], idCard[10:12], idCard[12:14])
	return birthday, nil
}

// 通过出生日期获取年龄
func GetAgeByBirthday(birthday string) (int, error) {
	birthday = strings.Trim(birthday, " \n\r\t")
	if len(birthday) == 8 && !strings.Contains(birthday, "-") {
		birthday = fmt.Sprintf("%s-%s-%s", birthday[0:4], birthday[4:6], birthday[6:8])
	}
	// 解析生日日期
	birth, err := time.Parse("2006-01-02", birthday)
	if err != nil {
		return 0, err
	}

	now := time.Now()

	// 计算年龄
	age := now.Year() - birth.Year()

	// 如果今年生日还没过，年龄减1
	if now.YearDay() < birth.YearDay() {
		age--
	}

	return age, nil
}

// RetainChinese 仅保留中文
func RetainChinese(str, skip, encoding string) string {
	var pattern string
	if encoding == "utf8" {
		pattern = "[\\p{Han}" + skip + "]+"
	} else {
		pattern = "[\\x80-\\xFF" + skip + "]+"
	}
	reg := regexp.MustCompile(pattern)
	result := reg.FindAllString(HtmlEntityDecode(str), -1)
	return strings.Join(result, "")
}

// StripEnglish 去除英文
func StripEnglish(str string) string {
	reg := regexp.MustCompile("[a-zA-Z]+")
	return reg.ReplaceAllString(str, "")
}

// StripNumber 去除数字
func StripNumber(str string) string {
	reg := regexp.MustCompile("[0-9]+")
	return reg.ReplaceAllString(str, "")
}

// HtmlEntityDecode 辅助函数，将实体编码转换为原始字符串
func HtmlEntityDecode(str string) string {
	return strings.ReplaceAll(str, "&amp;", "&")
}

// GetCmdParams 获取所有带 - 的参数
func GetCmdParams() map[string]string {
	var params = make(map[string]string)
	var key string
	for _, v := range os.Args {
		if v[0] == '-' {
			if strings.Contains(v, "=") {
				split := strings.Split(v, "=")
				params[split[0][1:]] = split[1]
				key = ""
			} else {
				key = v[1:]
			}
		} else {
			if len([]rune(key)) > 0 {
				params[key] = v
			}
		}
	}

	return params
}

// GetCmdParam 获取带 - 的参数
func GetCmdParam(key string) string {
	params := GetCmdParams()
	val, ok := params[key]
	if !ok {
		return ""
	}
	return val
}

// SnakeToCamel 将蛇形命名转换为驼峰命名
func SnakeToCamel(s string, upperFirst bool) string {
	var result string

	words := strings.Split(s, "_")

	for i, word := range words {
		if i == 0 {
			// 第一个单词
			if upperFirst {
				// 如果需要首字母大写
				caser := cases.Title(language.English)
				result += caser.String(strings.ToLower(word))
			} else {
				// 否则保持小写
				result += strings.ToLower(word)
			}
		} else {
			// 后续单词首字母大写
			caser := cases.Title(language.English)
			result += caser.String(strings.ToLower(word))
		}
	}

	return result
}

// CamelToSnake 将驼峰命名转换为蛇形命名
func CamelToSnake(s string) string {
	var result strings.Builder

	for i, char := range s {
		if char >= 'A' && char <= 'Z' {
			// 如果当前字符是大写字母
			if i > 0 {
				// 如果不是第一个字符，前面加一个下划线
				result.WriteRune('_')
			}
			// 将大写字母转换为小写
			result.WriteRune(char + 32)
		} else {
			// 其他字符直接写入
			result.WriteRune(char)
		}
	}

	return result.String()
}

func Base64Encode(s []byte) string {
	return base64.StdEncoding.EncodeToString(s)
}

func Base64Decode(s string) ([]byte, error) {
	return base64.StdEncoding.DecodeString(s)
}

func Uuid() string {
	return uuid.New().String()
}

func Md5(contents []byte) string {
	hash := md52.Sum(contents)
	return hex.EncodeToString(hash[:])
}

func Sha256(contents []byte) string {
	hash := sha256.Sum256(contents)
	return hex.EncodeToString(hash[:])
}

// GenerateSetStr 生成UPDATE SET 语句 name = ?, age = ?, created_at = ? 或 name = :1, age = :2, created_at = :3
func GenerateSetStr(ketArr []string, isNumber bool) string {
	if len(ketArr) <= 0 {
		return ""
	}
	var strArr []string
	for k, v := range ketArr {
		replace := If(isNumber, strconv.Itoa(k+1), "?")
		strArr = append(strArr, fmt.Sprintf("%s = %s", v, replace))
	}
	return strings.Join(strArr, ", ")
}

// StrRepeatJoin 生成重复的字符串，并且用特殊字符分割 ?,?,?
func StrRepeatJoin(count int, str string, join string) string {
	if count <= 0 {
		return ""
	}
	return strings.Repeat(str+join, count-1) + str
}

// StrNumberJoin 生成 :1, :2, :3
func StrNumberJoin(count int, join string) string {
	if count <= 0 {
		return ""
	}

	var strArr []string
	for i := range count {
		strArr = append(strArr, ":"+strconv.Itoa(i+1))
	}
	return strings.Join(strArr, join)
}
